# -*- coding: utf-8 -*-
"""
多算法彩票预测应用程序
集成了多种预测算法，消除随机投票机制
Author: LottoProphet Team
"""

import sys
import os
import io
from datetime import datetime
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QVBoxLayout, QPushButton, QLabel, 
    QComboBox, QWidget, QTextEdit, QSpinBox, QHBoxLayout, QTabWidget,
    QTableWidget, QTableWidgetItem, QHeaderView, QGroupBox, QCheckBox,
    QProgressBar, QSplitter
)
from PyQt5.QtCore import pyqtSignal, QObject, QThread, Qt
from PyQt5.QtGui import QFont
import numpy as np
import pandas as pd

# 设置编码
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")

# 检查依赖可用性
TORCH_AVAILABLE = False
PANDAS_AVAILABLE = False
SKLEARN_AVAILABLE = False

try:
    import torch
    TORCH_AVAILABLE = True
except ImportError:
    pass

try:
    import pandas as pd
    PANDAS_AVAILABLE = True
except ImportError:
    pass

try:
    from sklearn.preprocessing import MinMaxScaler
    SKLEARN_AVAILABLE = True
except ImportError:
    pass

class MultiAlgorithmPredictor(QObject):
    """多算法预测器核心类"""
    
    log_signal = pyqtSignal(str)
    progress_signal = pyqtSignal(int)  # 进度信号
    
    def __init__(self, lottery_type='ssq'):
        super().__init__()
        self.lottery_type = lottery_type
        self.ensemble_manager = None
        self.algorithms_initialized = False
        
        # 彩票参数
        if lottery_type == 'ssq':
            self.red_range = (1, 33)
            self.blue_range = (1, 16)
            self.red_count = 6
            self.blue_count = 1
        else:  # dlt
            self.red_range = (1, 35)
            self.blue_range = (1, 12)
            self.red_count = 5
            self.blue_count = 2
    
    def initialize_algorithms(self):
        """初始化算法系统"""
        self.log_signal.emit("🤖 初始化多算法系统...")
        
        try:
            # 尝试使用完整版集成管理器
            if TORCH_AVAILABLE and PANDAS_AVAILABLE:
                from ensemble_manager import EnsembleModelManager
                self.ensemble_manager = EnsembleModelManager(self.lottery_type)
                self.log_signal.emit("✅ 完整算法系统已初始化")
            else:
                from ensemble_manager import SimplifiedEnsembleManager
                self.ensemble_manager = SimplifiedEnsembleManager(self.lottery_type)
                self.log_signal.emit("✅ 简化算法系统已初始化")
            
            # 自动注册算法
            if hasattr(self.ensemble_manager, 'auto_register_algorithms'):
                count = self.ensemble_manager.auto_register_algorithms()
                self.log_signal.emit(f"📦 已注册 {count} 个算法")
            
            self.algorithms_initialized = True
            return True
            
        except Exception as e:
            self.log_signal.emit(f"❌ 算法初始化失败: {e}")
            return False
    
    def train_algorithms(self, historical_data):
        """训练所有算法"""
        if not self.algorithms_initialized:
            if not self.initialize_algorithms():
                return False
        
        self.log_signal.emit("🚀 开始训练多算法系统...")
        self.progress_signal.emit(10)
        
        try:
            if hasattr(self.ensemble_manager, 'train_all_algorithms'):
                results = self.ensemble_manager.train_all_algorithms(historical_data)
                trained_count = results.get('trained_algorithms', 0)
                self.log_signal.emit(f"✅ 训练完成，成功训练 {trained_count} 个算法")
                self.progress_signal.emit(100)
                return True
            else:
                self.log_signal.emit("⚠️ 使用简化模式，无需训练")
                self.progress_signal.emit(100)
                return True
                
        except Exception as e:
            self.log_signal.emit(f"❌ 训练失败: {e}")
            self.progress_signal.emit(0)
            return False
    
    def generate_predictions(self, recent_data, num_predictions=3, fusion_method='weighted_voting'):
        """生成多算法预测"""
        if not self.algorithms_initialized:
            self.log_signal.emit("⚠️ 算法未初始化，尝试初始化...")
            if not self.initialize_algorithms():
                return []
        
        self.log_signal.emit(f"🎯 生成 {num_predictions} 组预测（融合方法：{fusion_method}）")
        
        try:
            if hasattr(self.ensemble_manager, 'generate_ensemble_predictions'):
                predictions = self.ensemble_manager.generate_ensemble_predictions(
                    recent_data, num_predictions, fusion_method
                )
            else:
                predictions = self.ensemble_manager.generate_simple_predictions(num_predictions)
            
            self.log_signal.emit(f"✅ 成功生成 {len(predictions)} 组预测")
            return predictions
            
        except Exception as e:
            self.log_signal.emit(f"❌ 预测生成失败: {e}")
            # 返回备用预测
            return self._generate_backup_predictions(num_predictions)
    
    def _generate_backup_predictions(self, num_predictions):
        """生成备用预测"""
        import random
        predictions = []
        
        for i in range(num_predictions):
            red_balls = sorted(random.sample(
                range(self.red_range[0], self.red_range[1] + 1),
                self.red_count
            ))
            blue_balls = random.sample(
                range(self.blue_range[0], self.blue_range[1] + 1),
                self.blue_count
            )
            
            predictions.append({
                'red': red_balls,
                'blue': blue_balls,
                'algorithm': f'Backup-{i+1}',
                'confidence': 0.5
            })
        
        return predictions


class MultiAlgorithmThread(QThread):
    """多算法处理线程"""
    
    log_signal = pyqtSignal(str)
    progress_signal = pyqtSignal(int)
    finished_signal = pyqtSignal(list)  # 完成信号，携带预测结果
    
    def __init__(self, predictor, operation, **kwargs):
        super().__init__()
        self.predictor = predictor
        self.operation = operation
        self.kwargs = kwargs
        
        # 连接信号
        self.predictor.log_signal.connect(self.log_signal)
        self.predictor.progress_signal.connect(self.progress_signal)
    
    def run(self):
        try:
            if self.operation == 'train':
                historical_data = self.kwargs.get('historical_data')
                success = self.predictor.train_algorithms(historical_data)
                self.finished_signal.emit(['train_complete', success])
                
            elif self.operation == 'predict':
                recent_data = self.kwargs.get('recent_data')
                num_predictions = self.kwargs.get('num_predictions', 3)
                fusion_method = self.kwargs.get('fusion_method', 'weighted_voting')
                
                predictions = self.predictor.generate_predictions(
                    recent_data, num_predictions, fusion_method
                )
                self.finished_signal.emit(['predictions', predictions])
                
        except Exception as e:
            self.log_signal.emit(f"❌ 线程执行错误: {e}")
            self.finished_signal.emit(['error', str(e)])


class MultiAlgorithmLotteryApp(QMainWindow):
    """多算法彩票预测主应用"""
    
    def __init__(self):
        super().__init__()
        self.predictor = None
        self.current_predictions = []
        self.prediction_history = []
        
        self.initUI()
        self.log("🎰 多算法彩票预测系统启动")
        self.log(f"📊 依赖状态 - PyTorch: {'✅' if TORCH_AVAILABLE else '❌'}, "
                f"Pandas: {'✅' if PANDAS_AVAILABLE else '❌'}, "
                f"Sklearn: {'✅' if SKLEARN_AVAILABLE else '❌'}")
    
    def initUI(self):
        """初始化用户界面"""
        self.setWindowTitle("多算法彩票预测系统 v2.0")
        self.setGeometry(100, 100, 1200, 800)
        
        # 创建中央窗口
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 创建主布局
        main_layout = QHBoxLayout(central_widget)
        
        # 创建分割器
        splitter = QSplitter(Qt.Horizontal)
        main_layout.addWidget(splitter)
        
        # 左侧控制面板
        control_panel = self.create_control_panel()
        splitter.addWidget(control_panel)
        
        # 右侧结果面板
        result_panel = self.create_result_panel()
        splitter.addWidget(result_panel)
        
        # 设置分割比例
        splitter.setSizes([400, 800])
    
    def create_control_panel(self):
        """创建左侧控制面板"""
        panel = QWidget()
        layout = QVBoxLayout(panel)
        
        # 彩票类型选择
        lottery_group = QGroupBox("彩票类型")
        lottery_layout = QVBoxLayout(lottery_group)
        
        self.lottery_combo = QComboBox()
        self.lottery_combo.addItems(['双色球 (SSQ)', '大乐透 (DLT)'])
        self.lottery_combo.currentTextChanged.connect(self.on_lottery_type_changed)
        lottery_layout.addWidget(self.lottery_combo)
        
        layout.addWidget(lottery_group)
        
        # 预测设置
        prediction_group = QGroupBox("预测设置")
        prediction_layout = QVBoxLayout(prediction_group)
        
        # 预测数量
        num_layout = QHBoxLayout()
        num_layout.addWidget(QLabel("预测组数:"))
        self.num_predictions_spin = QSpinBox()
        self.num_predictions_spin.setRange(1, 10)
        self.num_predictions_spin.setValue(3)
        num_layout.addWidget(self.num_predictions_spin)
        prediction_layout.addLayout(num_layout)
        
        # 融合方法
        fusion_layout = QHBoxLayout()
        fusion_layout.addWidget(QLabel("融合方法:"))
        self.fusion_combo = QComboBox()
        self.fusion_combo.addItems([
            '加权投票 (weighted_voting)',
            '多数投票 (majority_voting)',
            '简单组合 (combination)'
        ])
        fusion_layout.addWidget(self.fusion_combo)
        prediction_layout.addLayout(fusion_layout)
        
        layout.addWidget(prediction_group)
        
        # 算法选择
        algorithm_group = QGroupBox("算法选择")
        algorithm_layout = QVBoxLayout(algorithm_group)
        
        self.algorithm_checkboxes = {}
        algorithms = [
            ('LSTM序列算法', 'lstm_sequence'),
            ('梯度提升算法', 'gradient_boosting'),
            ('模式记忆网络', 'pattern_memory'),
            ('Transformer注意力', 'transformer_attention'),
            ('区域权重算法', 'zone_weight')
        ]
        
        for name, key in algorithms:
            checkbox = QCheckBox(name)
            checkbox.setChecked(True)
            self.algorithm_checkboxes[key] = checkbox
            algorithm_layout.addWidget(checkbox)
        
        layout.addWidget(algorithm_group)
        
        # 操作按钮
        button_group = QGroupBox("操作")
        button_layout = QVBoxLayout(button_group)
        
        self.train_button = QPushButton("🚀 训练所有算法")
        self.train_button.clicked.connect(self.train_algorithms)
        button_layout.addWidget(self.train_button)
        
        self.predict_button = QPushButton("🎯 生成预测")
        self.predict_button.clicked.connect(self.generate_predictions)
        button_layout.addWidget(self.predict_button)
        
        self.analyze_button = QPushButton("🔍 模式分析")
        self.analyze_button.clicked.connect(self.analyze_patterns)
        button_layout.addWidget(self.analyze_button)
        
        layout.addWidget(button_group)
        
        # 进度条
        self.progress_bar = QProgressBar()
        layout.addWidget(self.progress_bar)
        
        # 日志区域
        log_group = QGroupBox("系统日志")
        log_layout = QVBoxLayout(log_group)
        
        self.log_text = QTextEdit()
        self.log_text.setMaximumHeight(200)
        self.log_text.setReadOnly(True)
        log_layout.addWidget(self.log_text)
        
        layout.addWidget(log_group)
        
        return panel
    
    def create_result_panel(self):
        """创建右侧结果面板"""
        panel = QWidget()
        layout = QVBoxLayout(panel)
        
        # 创建标签页
        self.tab_widget = QTabWidget()
        layout.addWidget(self.tab_widget)
        
        # 预测结果标签页
        self.prediction_tab = self.create_prediction_tab()
        self.tab_widget.addTab(self.prediction_tab, "🎯 预测结果")
        
        # 算法状态标签页
        self.status_tab = self.create_status_tab()
        self.tab_widget.addTab(self.status_tab, "📊 算法状态")
        
        # 历史记录标签页
        self.history_tab = self.create_history_tab()
        self.tab_widget.addTab(self.history_tab, "📈 历史记录")
        
        return panel
    
    def create_prediction_tab(self):
        """创建预测结果标签页"""
        tab = QWidget()
        layout = QVBoxLayout(tab)
        
        # 当前预测表格
        self.prediction_table = QTableWidget()
        self.prediction_table.setColumnCount(5)
        self.prediction_table.setHorizontalHeaderLabels([
            "算法", "红球", "蓝球", "置信度", "时间"
        ])
        
        # 设置表格属性
        header = self.prediction_table.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.Stretch)
        self.prediction_table.setAlternatingRowColors(True)
        
        layout.addWidget(QLabel("🎯 当前预测结果:"))
        layout.addWidget(self.prediction_table)
        
        # 预测统计
        stats_group = QGroupBox("预测统计")
        stats_layout = QVBoxLayout(stats_group)
        
        self.stats_label = QLabel("等待预测...")
        stats_layout.addWidget(self.stats_label)
        
        layout.addWidget(stats_group)
        
        return tab
    
    def create_status_tab(self):
        """创建算法状态标签页"""
        tab = QWidget()
        layout = QVBoxLayout(tab)
        
        # 算法状态表格
        self.status_table = QTableWidget()
        self.status_table.setColumnCount(4)
        self.status_table.setHorizontalHeaderLabels([
            "算法名称", "状态", "权重", "最后更新"
        ])
        
        header = self.status_table.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.Stretch)
        
        layout.addWidget(QLabel("📊 算法状态:"))
        layout.addWidget(self.status_table)
        
        return tab
    
    def create_history_tab(self):
        """创建历史记录标签页"""
        tab = QWidget()
        layout = QVBoxLayout(tab)
        
        # 历史记录表格
        self.history_table = QTableWidget()
        self.history_table.setColumnCount(4)
        self.history_table.setHorizontalHeaderLabels([
            "时间", "预测组数", "融合方法", "算法数量"
        ])
        
        header = self.history_table.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.Stretch)
        
        layout.addWidget(QLabel("📈 预测历史:"))
        layout.addWidget(self.history_table)
        
        return tab
    
    def on_lottery_type_changed(self, text):
        """彩票类型改变事件"""
        lottery_type = 'ssq' if 'SSQ' in text else 'dlt'
        self.log(f"🎲 切换到 {text}")
        
        # 重新初始化预测器
        self.predictor = MultiAlgorithmPredictor(lottery_type)
        self.current_predictions = []
        self.update_prediction_display()
    
    def train_algorithms(self):
        """训练算法"""
        if not self.predictor:
            lottery_type = 'ssq' if 'SSQ' in self.lottery_combo.currentText() else 'dlt'
            self.predictor = MultiAlgorithmPredictor(lottery_type)
        
        self.log("🚀 开始训练算法...")
        self.train_button.setEnabled(False)
        
        # 创建模拟历史数据
        historical_data = self.create_mock_historical_data(100)
        
        # 启动训练线程
        self.train_thread = MultiAlgorithmThread(
            self.predictor, 'train', historical_data=historical_data
        )
        self.train_thread.log_signal.connect(self.log)
        self.train_thread.progress_signal.connect(self.progress_bar.setValue)
        self.train_thread.finished_signal.connect(self.on_train_finished)
        self.train_thread.start()
    
    def generate_predictions(self):
        """生成预测"""
        if not self.predictor:
            lottery_type = 'ssq' if 'SSQ' in self.lottery_combo.currentText() else 'dlt'
            self.predictor = MultiAlgorithmPredictor(lottery_type)
        
        num_predictions = self.num_predictions_spin.value()
        fusion_method = self.fusion_combo.currentText().split('(')[1].replace(')', '')
        
        self.log(f"🎯 生成 {num_predictions} 组预测...")
        self.predict_button.setEnabled(False)
        
        # 创建模拟最近数据
        recent_data = self.create_mock_recent_data(10)
        
        # 启动预测线程
        self.predict_thread = MultiAlgorithmThread(
            self.predictor, 'predict',
            recent_data=recent_data,
            num_predictions=num_predictions,
            fusion_method=fusion_method
        )
        self.predict_thread.log_signal.connect(self.log)
        self.predict_thread.finished_signal.connect(self.on_predict_finished)
        self.predict_thread.start()
    
    def analyze_patterns(self):
        """分析模式"""
        self.log("🔍 执行模式分析...")
        
        # 这里可以添加模式分析的具体实现
        try:
            from pattern_analysis.consecutive_tracker import ConsecutivePatternTracker
            
            lottery_type = 'ssq' if 'SSQ' in self.lottery_combo.currentText() else 'dlt'
            tracker = ConsecutivePatternTracker(lottery_type)
            
            # 创建模拟数据进行分析
            historical_data = self.create_mock_historical_data(50)
            patterns = tracker.analyze_consecutive_patterns(historical_data)
            
            pattern_count = len(patterns.get('consecutive_patterns', {}))
            weight_count = len(patterns.get('pattern_weights', {}))
            
            self.log(f"✅ 模式分析完成")
            self.log(f"   发现连续模式: {pattern_count} 个")
            self.log(f"   计算权重: {weight_count} 个")
            
        except Exception as e:
            self.log(f"❌ 模式分析失败: {e}")
    
    def on_train_finished(self, result):
        """训练完成回调"""
        self.train_button.setEnabled(True)
        self.progress_bar.setValue(0)
        
        if result[0] == 'train_complete' and result[1]:
            self.log("✅ 算法训练完成！")
        else:
            self.log("❌ 算法训练失败")
    
    def on_predict_finished(self, result):
        """预测完成回调"""
        self.predict_button.setEnabled(True)
        
        if result[0] == 'predictions':
            predictions = result[1]
            self.current_predictions = predictions
            self.update_prediction_display()
            
            # 添加到历史记录
            self.prediction_history.append({
                'timestamp': datetime.now(),
                'predictions': predictions,
                'fusion_method': self.fusion_combo.currentText()
            })
            self.update_history_display()
        else:
            self.log(f"❌ 预测失败: {result[1]}")
    
    def update_prediction_display(self):
        """更新预测结果显示"""
        if not self.current_predictions:
            self.prediction_table.setRowCount(0)
            self.stats_label.setText("暂无预测结果")
            return
        
        # 更新预测表格
        self.prediction_table.setRowCount(len(self.current_predictions))
        
        for i, pred in enumerate(self.current_predictions):
            # 算法名称
            algorithm = pred.get('algorithm', 'Unknown')
            self.prediction_table.setItem(i, 0, QTableWidgetItem(algorithm))
            
            # 红球
            red_balls = pred.get('red', [])
            red_text = ', '.join(map(str, red_balls))
            self.prediction_table.setItem(i, 1, QTableWidgetItem(red_text))
            
            # 蓝球
            blue_balls = pred.get('blue', [])
            blue_text = ', '.join(map(str, blue_balls))
            self.prediction_table.setItem(i, 2, QTableWidgetItem(blue_text))
            
            # 置信度
            confidence = pred.get('confidence', 0.0)
            self.prediction_table.setItem(i, 3, QTableWidgetItem(f"{confidence:.2f}"))
            
            # 时间
            timestamp = datetime.now().strftime("%H:%M:%S")
            self.prediction_table.setItem(i, 4, QTableWidgetItem(timestamp))
        
        # 更新统计信息
        total_red = sum(len(pred.get('red', [])) for pred in self.current_predictions)
        total_blue = sum(len(pred.get('blue', [])) for pred in self.current_predictions)
        avg_confidence = sum(pred.get('confidence', 0) for pred in self.current_predictions) / len(self.current_predictions)
        
        stats_text = f"""
预测组数: {len(self.current_predictions)}
红球总数: {total_red}
蓝球总数: {total_blue}
平均置信度: {avg_confidence:.2f}
生成时间: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
        """.strip()
        
        self.stats_label.setText(stats_text)
    
    def update_history_display(self):
        """更新历史记录显示"""
        self.history_table.setRowCount(len(self.prediction_history))
        
        for i, record in enumerate(self.prediction_history):
            timestamp = record['timestamp'].strftime("%m-%d %H:%M")
            self.history_table.setItem(i, 0, QTableWidgetItem(timestamp))
            
            pred_count = len(record['predictions'])
            self.history_table.setItem(i, 1, QTableWidgetItem(str(pred_count)))
            
            fusion_method = record['fusion_method'].split('(')[0].strip()
            self.history_table.setItem(i, 2, QTableWidgetItem(fusion_method))
            
            # 统计使用的算法数量
            algorithms = set()
            for pred in record['predictions']:
                algorithms.add(pred.get('algorithm', 'Unknown'))
            
            self.history_table.setItem(i, 3, QTableWidgetItem(str(len(algorithms))))
    
    def create_mock_historical_data(self, num_periods):
        """创建模拟历史数据"""
        import random
        
        if PANDAS_AVAILABLE:
            data = []
            for i in range(num_periods):
                if 'SSQ' in self.lottery_combo.currentText():
                    red_balls = sorted(random.sample(range(1, 34), 6))
                    blue_ball = random.randint(1, 16)
                    period = red_balls + [blue_ball]
                else:  # DLT
                    red_balls = sorted(random.sample(range(1, 36), 5))
                    blue_balls = sorted(random.sample(range(1, 13), 2))
                    period = red_balls + blue_balls
                
                data.append(period)
            
            if 'SSQ' in self.lottery_combo.currentText():
                columns = ['Red_1', 'Red_2', 'Red_3', 'Red_4', 'Red_5', 'Red_6', 'Blue_1']
            else:
                columns = ['Red_1', 'Red_2', 'Red_3', 'Red_4', 'Red_5', 'Blue_1', 'Blue_2']
            
            return pd.DataFrame(data, columns=columns)
        else:
            # 简化版本，返回列表
            return [[random.randint(1, 33) for _ in range(7)] for _ in range(num_periods)]
    
    def create_mock_recent_data(self, num_periods):
        """创建模拟最近数据"""
        import random
        return np.random.randn(num_periods, 7) if 'numpy' in sys.modules else \
               [[random.uniform(0, 1) for _ in range(7)] for _ in range(num_periods)]
    
    def log(self, message):
        """记录日志"""
        timestamp = datetime.now().strftime("%H:%M:%S")
        formatted_message = f"[{timestamp}] {message}"
        
        self.log_text.append(formatted_message)
        self.log_text.ensureCursorVisible()
        
        # 同时输出到控制台
        print(formatted_message)


def main():
    """主函数"""
    app = QApplication(sys.argv)
    
    # 设置应用属性
    app.setApplicationName("多算法彩票预测系统")
    app.setApplicationVersion("2.0")
    
    # 创建主窗口
    main_window = MultiAlgorithmLotteryApp()
    main_window.show()
    
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()